#include <stdio.h>
#include <string.h>
#include <math.h>
#define PI		3.14159265358979323846

#include "defines.h"
#include "usr_color.h"
#include "comm.h"
#include "draw_staff.h"

int main(int argc, char *argv[])
{
	char filename[64] = "kernel.g6a";

	int i;

	char buf1[20];

	char buf2[20];

	char buf3[20];

	if (argc > 1)
	{
		strcpy(filename, argv[1]);
	}

	if (command_init(filename, "main") != 0)
		return -1;

	fprintf(stdout, "gen_kernel: wrting into file %s ...\n", filename);

	add_label("main");

/////////////// test algrithm ////////////////

//////////////////// mul is ok /////////////
	command_mov(1, REG(r, 11, 12, d), inum2str(buf1, 2, d));	// r11.12 = 2
	command_mul(1, REG(r, 11, 12, d), REG(r, 11, 12, d), REG(r, 11, 12, d));	// r11.12 = r11.12 * r11.12
	command_mul(1, REG(r, 11, 12, d), REG(r, 11, 12, d), REG(r, 11, 12, d));	// r11.12 = r11.12 * r11.12

	// assert(r11.12 == 16)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 12, d), "16:d");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

//////////////////// divmod div mod are ok now /////////////
	command_mov(1, REG(r, 12, 08, d), inum2str(buf1, 6, d));	// r12.08 = 6
	command_divmodint(1, REG(r, 11, 04, d), REG(r, 11, 08, d), REG(r, 11, 12, d), REG(r, 12, 08, d));	// r11.04 = r11.12 / r12.08 ... r11.08

	// assert(r11.04 == 2)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 04, d), "2:d");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");
	// assert(r11.08 == 4)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 08, d), "4:d");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_mov(1, REG(r, 11, 04, d), inum2str(buf1, 20, d));	// r11.04 = 20
	command_mov(1, REG(r, 12, 16, d), inum2str(buf1, 17, d));	// r12.16 = 17
	command_divint(1, REG(r, 11, 00, d), REG(r, 11, 04, d), REG(r, 12, 16, d));	// r11.04 = r11.04 / r12.16
	command_modint(1, REG(r, 11, 04, d), REG(r, 11, 04, d), REG(r, 12, 16, d));	// r11.04 = r11.04 % r12.16

	// assert(r11.00 == 1)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 00, d), "1:d");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");
	// assert(r11.04 == 3)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 04, d), "3:d");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

//////////////////// inverse is ok /////////////
	command_mov(1, REG(r, 11, 04, f), float2str(buf1, 0.25));	// r11.04 = 0.25
	command_mathfloat(1, REG(r, 11, 04, f), REG(r, 11, 04, f), INV);	// r11.04 = 1 / r11.04

	// assert(r11.04 == 4.0)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 04, f), "4.0:f");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

//////////////////// divfloat is ok /////////////
	command_divfloat(1, REG(r, 11, 04, f), float2str(buf1, 2.0), float2str(buf2, 0.5));	// r11.04 = 0.25 / 0.05

	// assert(r11.04 == 0.5)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 04, f), "4.0:f");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

//////////////////// EXP is ok /////////////
	command_mov(1, REG(r, 11, 00, f), float2str(buf1, 0.5));	// r11.04 = 0.5
	command_mathfloat(1, REG(r, 11, 00, f), REG(r, 11, 00, f), EXP);	// r11.04 = exp(r11.04)

	// assert(r11.04 == 1.4142136)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 00, f), "1.4142136:f");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

//////////////////// SQRT is ok /////////////
	command_mov(1, REG(r, 11, 04, f), float2str(buf1, 2));	// r11.04 = 2.0
	command_mathfloat(1, REG(r, 11, 04, f), REG(r, 11, 04, f), SQRT);	// r11.04 = sqrt(r11.04)

	// assert(r11.04 == 1.41421348)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 04, f), "1.41421348:f");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

//////////////////// POW is ok now /////////////
	command_mov(1, REG(r, 11, 04, f), float2str(buf1, 2));	// r11.04 = 2.0
	command_mov(1, REG(r, 12, 12, f), float2str(buf1, 0.5));	// r12.12 = 0.5
	command_powfloat(1, REG(r, 11, 00, f), REG(r, 11, 04, f), REG(r, 12, 12, f));	// r11.00 = pow(r11.04, 12.12)

	// assert(r11.00 == 1.4142136)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 11, 00, f), "1.4142136:f");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

//////////////////// type convertion /////////////
	command_mov(1, REG(r, 11, 00, f), float2str(buf1, -3.14159265358979));
	command_mov(1, REG(r, 12, 00, d), REG(r, 11, 00, f));

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 12, 00, d), "-3:d");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_mov(1, REG(r, 11, 00, d), inum2str(buf1, -3, d));
	command_mov(1, REG(r, 12, 00, f), REG(r, 11, 00, d));

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 12, 00, f), "-3.0:f");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

/////////////// test indirect addressing ////////////////

	command_mov(1, rnum2rname(buf1, 1, d), inum2str(buf2, 999, d));	// R(no1) = 999
	command_mov(1, rnum2rname(buf1, 2, ud), inum2str(buf2, rnum2addr(3), ud));	// put the addr of R(no3) into R(no2)

	// indirect addressing
	command_mov(1, REG_ADDR, rnum2rname(buf1, 2, ud));	// addr = R(no2)

	command_mov(1, REG_INDEX(d), rnum2rname(buf1, 1, d));	// store -- R[R(no2)] = R(no1);

	command_mov(1, rnum2rname(buf1, 4, d), REG_INDEX(d));	// load -- R(no4) = R[R(no2)];

///////////////// verify ////////////////

	// assert(r10.04 == 999) // R(no1)==999
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 04, d), "999:d");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	// assert(r10.04 == r10.12) // R(no1)==R(no3)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 04, d), REG(r, 10, 12, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	// assert(r10.08 == 0x014c) // R(no2)== addrof R(no3)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 08, d), "0x014c");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	// assert(r10.12 == r10.16) // R(no3)==R(no4)
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 12, d), REG(r, 10, 16, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

/////////////// test macro_push macro_pop ////////////////

	command_mov(1, REG(r, 10, 00, d), "30");
	command_mov(1, REG(r, 10, 04, d), "31");
	command_mov(1, REG(r, 10, 08, d), "32");
	command_mov(1, REG(r, 10, 12, d), "33");
	command_mov(1, REG(r, 10, 16, d), "34");
	command_mov(1, REG(r, 10, 20, d), "35");
	command_mov(1, REG(r, 10, 24, d), "36");
	command_mov(1, REG(r, 10, 28, d), "37");

	macro_push(0, 8);

	command_mov(1, REG(r, 10, 00, d), "0");
	command_mov(1, REG(r, 10, 04, d), "1");
	command_mov(1, REG(r, 10, 08, d), "2");
	command_mov(1, REG(r, 10, 12, d), "3");
	command_mov(1, REG(r, 10, 16, d), "4");
	command_mov(1, REG(r, 10, 20, d), "5");
	command_mov(1, REG(r, 10, 24, d), "6");
	command_mov(1, REG(r, 10, 28, d), "7");

	macro_push(0, 8);

	macro_pop(0, 4);			// reversed consequence pop
	macro_pop(4, 4);

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 00, d), "4");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 04, d), "5");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 08, d), "6");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 12, d), "7");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 16, d), "0");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 20, d), "1");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 24, d), "2");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 28, d), "3");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

///////// 

	macro_pop(4, 4);
	macro_pop(0, 4);

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 00, d), "30");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 04, d), "31");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 08, d), "32");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 12, d), "33");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 16, d), "34");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 20, d), "35");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 24, d), "36");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 10, 28, d), "37");
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

/////////////// push param ////////////////

	command_mov(1, rnum2rname(buf1, 10, d), inum2str(buf2, 90, d));
	command_mov(1, rnum2rname(buf1, 11, d), inum2str(buf2, 91, d));
	command_mov(1, rnum2rname(buf1, 12, d), inum2str(buf2, 92, d));
	command_mov(1, rnum2rname(buf1, 13, d), inum2str(buf2, 93, d));
	command_mov(1, rnum2rname(buf1, 14, d), inum2str(buf2, 94, d));
	command_mov(1, rnum2rname(buf1, 15, d), inum2str(buf2, 95, d));
	command_mov(1, rnum2rname(buf1, 16, d), inum2str(buf2, 96, d));
	command_mov(1, rnum2rname(buf1, 17, d), inum2str(buf2, 97, d));
	command_mov(1, rnum2rname(buf1, 18, d), inum2str(buf2, 98, d));
	command_mov(1, rnum2rname(buf1, 19, d), inum2str(buf2, 99, d));

	push_param(rnum2rname(buf1, 11, d));
	push_param(rnum2rname(buf1, 13, d));
	push_param(rnum2rname(buf1, 15, d));
	push_param(rnum2rname(buf1, 17, d));
	push_param(rnum2rname(buf1, 19, d));
	push_param(rnum2rname(buf1, 12, d));
	push_param(rnum2rname(buf1, 14, d));
	push_param(rnum2rname(buf1, 16, d));
	push_param(rnum2rname(buf1, 18, d));
	push_param(rnum2rname(buf1, 10, d));
	push_param(rnum2rname(buf1, 15, d));
	push_param(rnum2rname(buf1, 14, d));
	push_param(rnum2rname(buf1, 13, d));
	push_param(rnum2rname(buf1, 12, d));
	push_param(rnum2rname(buf1, 11, d));

//////////////// verify fast stack //////////////////////

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 127, 28, d), inum2str(buf1, 91, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 127, 24, d), inum2str(buf1, 93, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 127, 20, d), inum2str(buf1, 95, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");
	command_cmp(1, NOT_EQUAL, REG_COND, REG(r, 127, 16, d), inum2str(buf1, 97, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

/////////////////////////////////////////////////////////

	macro_pop(0, 15);

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 0, d), inum2str(buf2, 91, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 1, d), inum2str(buf2, 93, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 2, d), inum2str(buf2, 95, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 3, d), inum2str(buf2, 97, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 4, d), inum2str(buf2, 99, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 5, d), inum2str(buf2, 92, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 6, d), inum2str(buf2, 94, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 7, d), inum2str(buf2, 96, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 8, d), inum2str(buf2, 98, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 9, d), inum2str(buf2, 90, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 10, d), inum2str(buf2, 95, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 11, d), inum2str(buf2, 94, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 12, d), inum2str(buf2, 93, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 13, d), inum2str(buf2, 92, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

	command_cmp(1, NOT_EQUAL, REG_COND, rnum2rname(buf1, 14, d), inum2str(buf2, 91, d));
	condition(REG_COND);
	command_jmpi(1, "NOCROSS");

////////////// draw a cross or a bar ////////////////

	for (i = 250; i <= 263; i++)
	{
		draw_point(inum2str(buf1, i, uw), inum2str(buf2, 256, uw));
	}
	graph_set_color(inum2str(buf1, Y_BLUE, uw), inum2str(buf2, U_BLUE, uw),
					inum2str(buf3, V_BLUE, uw));
	for (i = 250; i <= 263; i++)
	{
		draw_point(inum2str(buf1, 256, uw), inum2str(buf2, i, uw));
	}

/*
	for (int j = 0; j < 15; j++)
		for (i = 0; i < 256; i+=3)
		{
			graph_set_color(inum2str(buf1, sin((i + 10 * j) * 4 * PI / 512.0) * 110 + 126, uw),
							inum2str(buf2, 0x80, uw), inum2str(buf2, 0x80, uw));
			draw_point(inum2str(buf1, i, uw), inum2str(buf2, 100 + 10 * j, uw));
		}
*/

	macro_return();

	add_label("NOCROSS");
	macro_EOT();

	command_terminate();

	return 0;
}
